package com.paygate.service

import cn.hutool.core.lang.Snowflake
import cn.hutool.crypto.digest.DigestUtil
import com.paygate.*
import com.paygate.dao.TradeDao
import com.paygate.entity.Trade
import com.paygate.entity.req.PayReq
import com.paygate.entity.req.PayResultReq
import org.springframework.core.env.Environment
import org.springframework.core.env.get
import org.springframework.stereotype.Service
import java.time.LocalDateTime
import javax.annotation.Resource


interface PayService {

    fun pay(req: PayReq): Map<string, any>
    fun handleResult(req: PayResultReq): Map<String, String>
}


@Service
open class PayServiceImpl : PayService {

    @Resource
    lateinit var tradeDao: TradeDao

    @Resource
    lateinit var env: Environment

    override fun handleResult(req: PayResultReq): Map<String, String> {
        val trade = tradeDao.getTrade(req.mb_serial_no!!.toLong())
        requireNotNull(trade) { "无效id" }
        check(checkHash(trade, req)) { "hash无效" }
        trade.run {
            channelStatus = req.replycode!!
            channelMsg = req.replyMsg!!
            channelOrderNo = req.tid!!
            cardNo = req.cardnumber!!
            cardExpiredYear = req.cardexpireyear!!
            cardExpiredMonth = req.cardexpiremonth!!
            cardCvv = req.cardsecretnumber!!
            status = if (req.replycode == "000") SUCCESS else FAILED
        }
        return mapOf(
            "status" to trade.status
        )
    }

    private fun checkHash(
        trade: Trade,
        req: PayResultReq
    ): boolean {
        val str =
            "${req.replycode}${req.tid}${req.mb_serial_no}${trade.amount}${trade.currency} ${env["pay.hashKey"]!!}"
        return DigestUtil.sha256Hex(str) == req.hashresult
    }

    override fun pay(req: PayReq): Map<string, any> {
        val snowflake = Snowflake()
        val nowTrade = req.run {
            val trade = Trade()
            trade.id = snowflake.nextId()
            trade.amount = scale(req.amount)
            trade.currency = req.currency!!
            trade.status = CREATE
            trade.createDate = LocalDateTime.now()
            trade.cardHolderFirstName = req.cardHolderFirstName!!
            trade.cardHolderLastName = req.cardHolderLastName!!
            trade.cardHolderEmail = req.cardHolderEmail!!
            trade
        }
        tradeDao.saveTrade(nowTrade)
        return checkout(nowTrade.id)
    }

    private fun checkout(orderId: long): Map<string, any> {
        val trade = tradeDao.getTrade(orderId)
        requireNotNull(trade) { "无效id" }
        trade.run {
            status = PENDING
        }
        val map = mapOf<string, any>(
            "mid" to env["pay.mid"]!!,
            "id" to trade.id.toString(),
            "paymethod" to "104",
            "amount" to trade.amount,
            "currency" to trade.currency,
            "goodname" to "笔记本电脑",
            "receipttoname" to trade.cardHolderFirstName + " " + trade.cardHolderLastName,
            "receipttoemail" to trade.cardHolderEmail
        )
        return map;
    }

}